/* ==============================================================================
*
*   Copyright (c) 2010, Pierre Favier
*   All rights reserved.
*
*   NTasking is free software: you can redistribute it and/or modify it
*   under the terms of the GNU General Public License as published by the
*   Free Software Foundation.
*
*   Redistribution and use in source and binary forms, with or without
*   modification, are permitted provided that the following conditions
*   are met:
*
*   -   Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*
*   -   Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials
*       provided with the distribution.
*
*   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
*   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
*   BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
*   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
*   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
*   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
*   THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*   SUCH DAMAGE.
*
* ============================================================================== */

using System;
using NUnit.Framework;
using Rhino.Mocks;
using Rhino.Mocks.Constraints;

namespace NTasking.ValidationTests.ACATS_3_0.B9
{

    [TestFixture(Description = "")]
    public class B954001 : ValidationTest
    {

        private static Distributor_2 d2;
        private static Distributor_4 d4;
        private static CreditComputation cc;
        private static ErrorRouter er;


        private class Transaction
        {

            internal int ID { get; set; }

            internal int AccountNumber { get; set; }

        }


        private class Distributor_2 : ValidationTestTask
        {

            [Entry]
            internal Action<Transaction> Input { get; private set; }


            internal Distributor_2(IValidationTestResult result)
                : base(result)
            {
            }


            protected override void Body()
            {
                Accept(Input, (transaction) =>
                {
                    Result.Accepted(Input);
                    Requeue(cc.Input);
                });
            }

        }


        private class Distributor_4 : ValidationTestTask
        {

            [Entry]
            internal Action<Transaction> Input { get; private set; }


            internal Distributor_4(IValidationTestResult result)
                : base(result)
            {
            }


            protected override void Body()
            {
                Accept(Input, (transaction) =>
                {
                    Result.Accepted(Input);
                    RequeueWithAbort(cc.Input);
                });
            }

        }


        private class CreditComputation : ValidationTestTask
        {

            [Entry]
            internal Action<int> Input { get; private set; }


            internal CreditComputation(IValidationTestResult result)
                : base(result)
            {
            }


            protected override void Body()
            {
                Accept(Input, (accountNumber) =>
                {

                });
            }

        }


        private class ErrorRouter : ValidationTestTask
        {

            [Entry]
            internal Action UnknownError { get; private set; }

            
            [Entry]
            internal Action<Transaction> InputError { get; private set; }


            internal ErrorRouter(IValidationTestResult result)
                : base(result)
            {
            }


            protected override void Body()
            {
                Select(s => s.
                    Accept(UnknownError, () =>
                    {
                        Result.Accepted(UnknownError);

                        // a reasonable, but wrong, assumption is that we could requeue
                        // back to where we came from.  The fact that this entry does 
                        // not have any parameters prevents us from going back to an
                        // entry with parameters.

                        Requeue(InputError);
                    }).
                Or.
                    Accept(InputError, (transaction) =>
                    {
                        Result.Accepted(InputError);
                        Requeue(UnknownError);
                    })
                );
            }

        }


        [Test]
        [Description(
            "Check for error if requeue is not type conformant with the call " +
            "or if requeue has parameters. Check requeues with/without abort.")]
        public void Test()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();

            Ada.Declare(() =>
            {
                d2 = new Distributor_2(result);
                d4 = new Distributor_4(result);
                cc = new CreditComputation(result);
                er = new ErrorRouter(result);

                // Setup text expectations

                Expect.Call(() => result.Accepted(d2.Input));
                Expect.Call(() => result.TaskThrewException(null, null, 0)).
                    IgnoreArguments().
                    Constraints(Is.Same(d2), Is.TypeOf(typeof(SyntaxError)), Is.Equal(Errors.RequeueProfileMismatchError));

                Expect.Call(() => result.Accepted(d4.Input));
                Expect.Call(() => result.TaskThrewException(null, null, 0)).
                    IgnoreArguments().
                    Constraints(Is.Same(d4), Is.TypeOf(typeof(SyntaxError)), Is.Equal(Errors.RequeueProfileMismatchError));

                Expect.Call(() => result.Accepted(er.InputError));
                Expect.Call(() => result.Accepted(er.UnknownError));
                Expect.Call(() => result.TaskThrewException(null, null, 0)).
                    IgnoreArguments().
                    Constraints(Is.Same(er), Is.TypeOf(typeof(SyntaxError)), Is.Equal(Errors.RequeueProfileMismatchError));

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
                // Start test execution

                try
                {
                    d2.Input(null);
                }
                catch
                {
                }

                try
                {
                    d4.Input(null);
                }
                catch
                {
                }

                try
                {
                    er.InputError(null);
                }
                catch
                {
                }

                cc.Input(0);
            });
        }

    }

}
